#!/usr/bin/python
"""
calc.py

Simple calculator using the annex lexer and parser.
"""

from pprint import pprint
import sys

import annex


#
# Lexer (state machine)
#

SIGN_MAP = {
    '+': 'PLUS',
    '-': 'MINUS',
    }


# TODO: Specify these in CRE syntax.
LEXER = {
    'start': [
        # digit+ any digit+
        ('digit+ "." digit+', annex.SimpleToken('REAL')),
        # digit+
        ('digit+', annex.SimpleToken('INTEGER')),
        # chars[+ -]
        ('chars[+ hyphen]', annex.MappedTokenValue('SIGN', SIGN_MAP)),
        # this is ignored
        # whitespace+
        ('space+',),
        ]
    }


#
# Parser (rules and actions)
#


RULES = """
Sum <- Number (SIGN Number)*
Number <- REAL / INTEGER
"""


def Sum(parsed):
  print '\tSum', parsed
  assert len(parsed) == 2, parsed
  left, pairs = parsed

  sum_ = left

  tree = []
  for (mult, num) in pairs:
    sum_ += mult * num

  return sum_


def Number(parsed):
  print '\tNumber', parsed
  _, expr = parsed  # don't need index
  return expr


def REAL(parsed):
  # NOTE: This conversion could be done in the lexing step.
  print 'REAL', parsed
  _, value, _ = parsed
  return float(value)


def INTEGER(parsed):
  # NOTE: This conversion could be done in the lexing step.
  _, value, _ = parsed
  return int(value)

# TODO: There should be helpers just to return the value?  Although you need an
# error API with line numbers to indicate errors in the parser.

def SIGN(parsed):
  _, value, _ = parsed
  if value == 'PLUS':
    mult = 1
  elif value == 'MINUS':
    mult = -1
  return mult


def main(argv):
  """Returns an exit code."""

  calc = annex.build_language(__name__)
  print calc

  print '--'
  result, pos = calc.parse(' 1.0+ 2.343 - 4', start='Sum')
  print '--'

  print pos
  pprint(result)


if __name__ == '__main__':
  main(sys.argv)
